<template>
  <div>
    <el-upload
      ref="fileUpload"
      v-model:file-list="fileList"
      :multiple="multiple"
      :action="uploadFileUrl"
      :headers="headers"
      :before-upload="handleBeforeUpload as any"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      :on-success="handleUploadSuccess"
      :on-remove="handleRemove"
      :on-change="handleChange"
      :show-file-list="showFileList"
      :data="params"
      :disabled="uploadDisabled"
      :name="binaryName"
      :auto-upload="autoUpload"
      :list-type="listType as any"
      :on-preview="handleVideoPreview"
      :class="listType !== 'text' && fileList.length === limit ? 'hideUpload' : ''"
    >
      <template #default>
        <slot v-if="isSlot"></slot>
        <el-button
          v-if="!isSlot"
          :type="buttonType as any"
          :icon="buttonIcon"
          :disabled="disabled"
          :loading="loading"
          :style="{ width: `${buttonWidth}px` }"
          @click="emits('click')"
        >
          {{ uploadFileButtonName }}
        </el-button>
      </template>
    </el-upload>

    <!-- 视频预览区域 -->
    <video
      v-if="previewVideoUrl"
      controls
      style="width: 100%; max-height: 400px; margin-top: 20px"
      :src="previewVideoUrl"
    ></video>
  </div>
</template>

<script setup lang="ts">
import {
  type UploadProps,
  type UploadFile,
  type UploadFiles,
  type UploadRawFile,
  ElLoading,
  ElMessage
} from 'element-plus'
import { useUserStoreWithOut } from '@/store/modules/user'
import { saveAs } from 'file-saver'

interface Props {
  url: string
  limit?: number | undefined
  fileSize?: number | undefined
  multiple?: boolean | undefined
  uploadFileButtonName?: string
  fileType?: string[]
  params?: any
  disabled?: boolean | undefined
  uploadDisabled?: boolean | undefined
  autoUpload?: boolean
  showFileList?: boolean
  buttonWidth?: string | number
  buttonIcon?: string
  buttonType?: string
  customErrorAlert?: boolean
  binaryName?: string
  isSlot?: boolean
  fullLoading?: boolean
  tokenKey?: string
  listType?: string
  cover?: boolean
  uploadSuccessRes?: () => void
  handleRemoveFile?: () => void
  fileListMap?: any[]
  downloadFile?: (url: string) => void
  tempVisible?: boolean
  downloadTempData?: { url: string; downloadFormat: string } | undefined
}

const props = withDefaults(defineProps<Props>(), {
  url: '',
  limit: 1, // 视频一般较大，可以限制数量为1
  fileSize: 1000, // 视频较大，设置更高的MB上限
  buttonWidth: 76,
  buttonIcon: '',
  buttonType: 'primary',
  binaryName: 'file',
  multiple: false,
  disabled: false,
  uploadDisabled: false,
  fileType: () => ['mp4', 'avi', 'mov'], // 添加视频格式
  uploadFileButtonName: 'upload',
  params: () => ({}),
  autoUpload: true,
  showFileList: false,
  customErrorAlert: false,
  isSlot: false,
  fullLoading: false,
  listType: 'text',
  tokenKey: 'Authorization',
  tempVisible: false,
  cover: false,
  downloadTempData: () => ({ url: '', downloadFormat: '' }),
  // @ts-ignore
  uploadSuccessRes: () => {},
  // @ts-ignore
  handleRemoveFile: () => {},
  fileListMap: () => [],
  downloadFile: () => {}
})

const emits = defineEmits([
  'uploadSuccessRes',
  'handClickUpload',
  'update:file',
  'handlePictureCardPreview',
  'click',
  'handleRemoveFile',
  'uploadError'
])
const {
  url,
  limit,
  multiple,
  fileSize,
  fileType,
  disabled,
  uploadDisabled,
  uploadFileButtonName,
  params,
  autoUpload,
  showFileList,
  buttonWidth,
  buttonIcon,
  buttonType,
  customErrorAlert,
  binaryName,
  isSlot,
  listType,
  tokenKey,
  uploadSuccessRes,
  handleRemoveFile,
  fileListMap,
  downloadFile,
  fullLoading,
  tempVisible,
  downloadTempData,
  cover
} = toRefs(props)

const userStore = useUserStoreWithOut()

const uploadFileUrl = computed(() => `${import.meta.env.VITE_API_BASE_PATH}${url.value}`)
const headers = computed(() => ({
  [tokenKey.value ?? 'Authorization']: userStore.getToken ?? ''
}))

const fileUpload = ref()
const fileList = ref<any[]>([])
const loading = ref<boolean>(false)
const fullLoadingInstance = ref<Record<string, any>>({})
const fileId = ref<number>(1)
const previewVideoUrl = ref<string | null>(null) // 用于存储要预览的视频URL

watch(
  fileListMap,
  () => {
    if (showFileList.value && fileListMap.value) fileList.value = fileListMap.value
  },
  { immediate: true }
)

const handDownloadTemp = () => {
  if (tempVisible.value) {
    saveAs(downloadTempData.value.url, downloadTempData.value.downloadFormat)
  }
}

// 上传前校检格式和大小
const handleBeforeUpload: UploadProps['beforeUpload'] = (file: any) => {
  if (fullLoading.value) {
    fullLoadingInstance.value = ElLoading.service({
      text: '正在上传文件，请稍候',
      background: 'rgba(0, 0, 0, 0.7)'
    })
  }
  loading.value = true
  // 校检文件类型
  if (fileType.value.length) {
    const fileName = file.name.split('.')
    const fileExt = fileName[fileName.length - 1]
    const isTypeOk = fileType.value.indexOf(fileExt) >= 0
    if (!isTypeOk) {
      ElMessage.warning({
        message: `文件格式不正确, 请上传${fileType.value.join('/')}格式文件!`
      })
      loading.value = false
      if (fullLoading.value) fullLoadingInstance.value.close()
      return false
    }
  }
  // 校检文件大小
  if (fileSize.value) {
    const isLt = file.size / 1024 / 1024 < fileSize.value
    if (!isLt) {
      ElMessage.error({
        message: `上传文件大小不能超过 ${fileSize.value} MB!`
      })
      loading.value = false
      if (fullLoading.value) fullLoadingInstance.value.close()
      return false
    }
  }
  return true
}
// 文件个数超出
const handleExceed: UploadProps['onExceed'] = (files) => {
  loading.value = false
  if (fullLoading.value) fullLoadingInstance.value.close()

  if (cover.value) {
    fileUpload.value!.clearFiles()
    const file = files[0] as UploadRawFile
    const genFileId = () => Date.now() + fileId.value++
    file.uid = genFileId()
    fileUpload.value!.handleStart(file)
    if (autoUpload.value) {
      fileUpload.value!.submit()
    }
  } else {
    ElMessage.error({
      message: `上传文件数量不能超过 ${limit.value} 个!`
    })
  }
}
// 上传失败
const handleUploadError: UploadProps['onError'] = (error: any) => {
  loading.value = false
  if (fullLoading.value) fullLoadingInstance.value.close()
  if (!customErrorAlert.value) {
    ElMessage.error({
      message: `上传文件失败`,
      duration: 4000
    })
  } else {
    ElMessage.error({
      message: `上传文件失败：${JSON.parse(error.message).message}`,
      duration: 4000
    })
  }
}
// 上传成功回调
const handleUploadSuccess: UploadProps['onSuccess'] = (res, uploadFile: UploadFile) => {
  if (res.code == 0 || res.code == 200) {
    if (!showFileList.value) fileList.value = []
    loading.value = false
    if (fullLoading.value) fullLoadingInstance.value.close()
    if (!customErrorAlert.value) {
      ElMessage.success({
        message: '文件上传成功'
      })
    }
    // @ts-ignore
    if (uploadSuccessRes.value) uploadSuccessRes.value({ res: res.data, fileList: fileList.value })
    emits('uploadSuccessRes', { ...res.data, uploadFile })
  } else {
    if (!showFileList.value) fileList.value = []
    loading.value = false
    if (fullLoading.value) fullLoadingInstance.value.close()
    if (!customErrorAlert.value) {
      ElMessage.error({
        message: res.msg || res.message
      })
    }
    emits('uploadError', res.msg || res.message)
  }
}
const handleChange: UploadProps['onChange'] = (
  // @ts-ignore
  uploadFile: UploadFile,
  uploadFiles: UploadFiles
) => {
  if (!autoUpload.value) {
    const Files = uploadFiles.map((item: Record<string, any>) => item.raw)
    if (multiple.value) {
      emits('update:file', Files)
    } else {
      emits('update:file', Files[0])
    }
  }
}

const handleRemove: UploadProps['onRemove'] = (
  // @ts-ignore
  uploadFile: UploadFile,
  uploadFiles: UploadFiles
) => {
  if (!autoUpload.value) {
    const Files = uploadFiles.map((item: Record<string, any>) => item.raw)
    if (multiple.value) {
      emits('update:file', Files)
    } else {
      emits('update:file', Files)
    }
  }
  previewVideoUrl.value = null
  emits('handleRemoveFile', uploadFile)
  // @ts-ignore
  if (handleRemoveFile.value) handleRemoveFile.value(fileList.value)
}

// 视频预览功能
const handleVideoPreview: UploadProps['onPreview'] = (uploadFile) => {
  const file = fileList.value.find((item: any) => item.uid === uploadFile.uid)
  const url = file?.response?.data?.url ?? file.url
  if (url) {
    previewVideoUrl.value = url // 设置视频URL以在<video>标签中播放
  } else {
    ElMessage.error('无法预览视频')
  }
}

defineExpose({ fileList })
</script>

<style lang="less" scoped>
.hideUpload :deep(.el-upload--picture-card) {
  display: none !important;
}
</style>
